#include "ModelFactory.h"
#include "Library.h"

Pointer<Model> CreateModelFromMdl( MdlFile& file )
{
	Pointer<Model> model = new Model();
	unsigned int meshCount = file.meshes.size();
	model->getMeshes().resize(meshCount);
	VertexType::Vector_t params;


	for (unsigned int i = 0; i < meshCount; i++)
	{
		for (unsigned int j = 0; j < file.meshes[i].parameters.size(); ++j)
		{
			params.push_back(VertexType( file.meshes[i].parameters[j].m_offset,
										 file.meshes[i].parameters[j].m_size,
										 (VertexParameter)file.meshes[i].parameters[j].m_parameter ));
		}

		model->getMeshes()[i] = new Mesh(Pointer<IVertexContainer>(new IVertexContainer(VertexDeclaration(params))));
		
		memcpy(model->getMeshes()[i]->getMaterial().m_ambient, file.meshes[i].material.ambient, sizeof(float) * 4);
		memcpy(model->getMeshes()[i]->getMaterial().m_diffuse, file.meshes[i].material.diffuse, sizeof(float) * 4);
		memcpy(model->getMeshes()[i]->getMaterial().m_emmisive, file.meshes[i].material.emmisive, sizeof(float) * 4);
		memcpy(model->getMeshes()[i]->getMaterial().m_specular, file.meshes[i].material.specular, sizeof(float) * 4);
		model->getMeshes()[i]->getMaterial().m_shader = file.meshes[i].material.shaderName;
		model->getMeshes()[i]->getMaterial().m_shininess = file.meshes[i].material.shininess;

		for (std::vector<MdlFileUniform>::iterator it = file.meshes[i].uniforms.begin(); it != file.meshes[i].uniforms.end(); ++it)
		{
			//std::string& uniformType = it->uniformType;
			//if (HashedString(uniformType) == AttachSkeletonInstance::type)
			//{	
			//	Pointer<UniformInstruction> instructions((UniformInstruction*) new AttachSkeletonInstance());
			//				//													**********0******
			//	material.m_uniforms.insert( Material::UniformIDElementsInstructionPair_t( 0, Material::UniformElementsInstructionPair_t( numberOfElements, instructions ) ) );
			//} else if (HashedString(uniformType) == AttachTime::type)
			//{
			//	Pointer<UniformInstruction> instructions((UniformInstruction*) new AttachTime());
			//				//													**********0******
			//	material.m_uniforms.insert( Material::UniformIDElementsInstructionPair_t( 0, Material::UniformElementsInstructionPair_t( numberOfElements, instructions ) ) );
			//}
		}

		model->getMeshes()[i]->getVertexContainer()->resize(file.meshes[i].vertexCount);
		memcpy(model->getMeshes()[i]->getVertexContainer()->getVertexPointer(), &(file.meshes[i].vertexData[0]), file.meshes[i].vertexCount * model->getMeshes()[i]->getVertexContainer()->getVertexDeclaration().m_vertexSize);
	}
	if (Library::getSingletonPtr())
	{
		Pointer<IResource> resource;
		CopyPointer(model, resource);
		Library::getSingleton().AddResource(file.modelName, resource);
	}
	return model;
}

Pointer<ModelInstance> CreateModelInstance( Pointer<Model>& model )
{
	Pointer<ModelInstance> modelInstance = new ModelInstance(model);
	
	// Iterate through each mesh
	for (Mesh::Vector_t::iterator mesh = model->getMeshes().begin(); mesh != model->getMeshes().end(); ++mesh)
	{
		MeshInstance meshInstance( *mesh );
		
		for (UniformCountInstructionMap_t::iterator it = (*mesh)->getUniformInstructions().begin(); it != (*mesh)->getUniformInstructions().end(); ++it)
		{
			//const UniformID& id = it->first;
			//const UniformElements& elements = it->second.first;
			//Pointer<UniformInstruction> instruction = it->second.second;

			//if ( instruction->getType() == AttachSkeletonInstance::type )
			//{
			//	if (modelInstance->getSkeletonInstance().isValid())
			//	{
			//		UniformIDElementsLocationPair_t uniform(id, UniformElementsLocationPair_t( elements, &(modelInstance->getSkeletonInstance()->getGlobalMatrices()[0]) ) );
			//		matInstance.getUniforms().insert(uniform);
			//	}
			//} else if ( instruction->getType() == AttachTime::type )
			//{
			//	UniformIDElementsLocationPair_t uniform(id, UniformElementsLocationPair_t( elements, &(GlobalTimer::getTime().getMilliSecondsSinceStart()) ));
			//	matInstance.getUniforms().insert(uniform);
			//}
		}
		modelInstance->getMeshInstances().push_back(meshInstance);
	}
	return modelInstance;
}